package com.tj.collection.task;

import com.alibaba.fastjson.JSON;
import com.dangdang.ddframe.job.api.ShardingContext;
import com.dangdang.ddframe.job.api.simple.SimpleJob;
import com.fqgj.base.services.redis.RedisClient;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.log.factory.LogFactory;
import com.fqgj.log.interfaces.Log;
import com.google.common.collect.Lists;
import com.tj.collection.bean.RedisKey;
import com.tj.collection.bean.SystemConstants;
import com.tj.collection.db.dao.*;
import com.tj.collection.db.domain.Admin;
import com.tj.collection.db.entity.*;
import com.tj.collection.db.service.AdminService;
import com.tj.collection.enums.*;
import com.tj.collection.utils.ConfigUtil;
import com.tj.collection.utils.SerialNumberUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: sm
 * Date: 2019-09-04
 * Time: 14:41
 * <p>
 * 该任务用于触发转单逻辑 比如 s1->s2
 */
@Component
public class StageTransferJob implements SimpleJob {
    private static final Log LOGGER = LogFactory.getLog(StageTransferJob.class);

    @Autowired
    private ClAllocationBatchDao allocationBatchDao;

    @Autowired
    private ClAllocationDetailDao allocationDetailDao;

    @Autowired
    private ClStageDao stageDao;

    @Autowired
    private ClReceiverDao receiverDao;

    @Autowired
    private ConfigUtil configUtil;

    @Autowired
    private ClAgentsDao agentsDao;

    @Autowired
    private AdminService adminService;

    @Autowired
    private RedisClient redisClient;

    @Override
    public void execute(ShardingContext shardingContext) {
        if (!configUtil.isStageTransferSwitchOpen()) {
            LOGGER.info("开始进入stage transfer,开关未开启");
            return;
        }
        this.run();
    }

    /**
     * 执行任务
     */
    public void run() {
        LOGGER.info("更新逾期天数开始");
        receiverDao.updateOverdueDays();
        LOGGER.info("更新逾期天数结束");

        int indexOfWeek = 0;
        try {
            indexOfWeek = DateUtil.dayForWeek(DateUtil.getDate(new Date()));
        } catch (Exception e) {
        }
        //每周一S1全量撤单 重新分配
        String dateStr = DateUtil.getDate(new Date(), "yyyy-MM-dd");
        if (indexOfWeek == 7 && !configUtil.getCollectionNoShuffleDate().contains(dateStr)) {
            int count = allocationBatchDao.countBatchByDate(DateUtil.getPatternDate(new Date(), "yyyy-MM-dd"));
            if (count == 0) {
                LOGGER.info("周一撤单");
                List<ClStageEntity> clStageEntityList = stageDao.selectMStages();
                for (ClStageEntity entity : clStageEntityList) {
                    int num = this.cancelAllOrders(entity.getStageCode());
                    LOGGER.info("周一撤单,stageCode:{},{}", entity.getStageCode(), num);
                }
            } else {
                LOGGER.info("已触发过撤单任务,不再执行,{}", count);
            }
        }

        List<ClAllocationBatchEntity> batchNeedsTransfer = getBatchNeedsTransfer();
        LOGGER.info("需要更新的batch数据,size:{}", batchNeedsTransfer.size());

        for (ClAllocationBatchEntity batchEntity : batchNeedsTransfer) {
            try {
                ClAgentsEntity agentsEntity = agentsDao.getByAdminId(batchEntity.getAdminId());
                if (agentsEntity == null) {
                    LOGGER.error("batchsNeedsTransfer,催收员不存在,adminId:{},bt:{}", batchEntity.getAdminId(), batchEntity.getBatchNo());
                    continue;
                }

                if (agentsEntity.getType().equals(AgentTypeEnum.INTERNAL.getType())) {
                    resetBatchOrdersToWaitingForAllocation(batchEntity);
                } else {
                    //如果是外催 那么直接复制该批次到下一个阶段的该类型催收
                    Integer nextAdminId = agentsEntity.getNextAdminId();
                    moveBatchToAnotherAgent(batchEntity, nextAdminId);
                }
            } catch (Exception e) {
                LOGGER.error("batchsNeedsTransfer失败,batch:{}", batchEntity.getBatchNo(), e);
            }
        }

        //每天重新分单
        try {
            updateBatch();
        } catch (Exception e) {
            LOGGER.error("== 处理刷新 失败 ==", e);
        }

        String date = DateUtil.getDate(new Date());
        redisClient.set(RedisKey.COLLECTION_ALLOCATION_DAILY_KEY, date, 86400, date);
    }

    /**
     * 全量撤单
     *
     * @param stageCode
     */
    public int cancelAllOrders(String stageCode) {
        int total = 0;
        List<ClAllocationBatchEntity> batchEntityList = allocationBatchDao.getAllActiveBatchByStageCode(stageCode);
        LOGGER.info("需要撤单的批次数,stageCode:{},size:{}", stageCode, batchEntityList.size());
        for (ClAllocationBatchEntity batchEntity : batchEntityList) {
            try {
                int num = allocationDetailDao.updateStatusByBatchNoAndStatus(batchEntity.getBatchNo(),
                        Lists.newArrayList(AllocationStatusEnum.INIT.getStatus(), AllocationStatusEnum.COLLECTING.getStatus()),
                        AllocationStatusEnum.INVALID.getStatus()
                );
                total = total + num;

                Integer num1 = null;
                int overdueDays = DateUtil.diffDate(new Date(), batchEntity.getRepaymentDt());
                if (overdueDays <= 99999) {
                    num1 = receiverDao.updateStatusByBatchNo(batchEntity.getBatchNo(), ReceiverStatusEnum.INIT.getStatus());
                } else {
                    num1 = receiverDao.updateStatusByBatchNo(batchEntity.getBatchNo(), ReceiverStatusEnum.COLLECTION_END.getStatus());
                }
                batchEntity.setStatus(AllocationBatchEnum.OVERDUE.getStatus());
                allocationBatchDao.updateByPrimaryKey(batchEntity);

                if (num != num1) {
                    LOGGER.warn("批次撤单数量不符,batchNo:{}", batchEntity.getBatchNo());
                }

                LOGGER.info("批次撤单成功,batchNo:{},num:{},num1", batchEntity.getBatchNo(), num, num1);
            } catch (Exception e) {
                LOGGER.error("batchsNeedsTransfer失败,batch:{}", batchEntity.getBatchNo(), e);
            }
        }
        LOGGER.info("撤单完成,stageCode:{}", stageCode);
        return total;
    }

    /**
     * 复制批次订单
     *
     * @param allocationBatchEntity
     * @param nextAdminId
     */
    private void moveBatchToAnotherAgent(ClAllocationBatchEntity allocationBatchEntity, Integer nextAdminId) {
        allocationBatchEntity.setStatus(AllocationBatchEnum.OVERDUE.getStatus());
        allocationBatchDao.updateByPrimaryKey(allocationBatchEntity);

        Admin oneAdminByAdmin = adminService.getOneAdminByAdmin(Long.valueOf(nextAdminId));
        ClAgentsEntity byAdminId = agentsDao.getByAdminId(nextAdminId);

        LOGGER.info("== moveBatchToAnotherAgent ==,nextAdminId:{},batchNo:{},oldAdmin:{}", nextAdminId, allocationBatchEntity.getBatchNo(), allocationBatchEntity.getAdminId());
        String newBatchNo = SerialNumberUtil.getBizOrderNumber(AdminNumberRuleEnum.BATCH);
        ClAllocationBatchEntity batchEntity = new ClAllocationBatchEntity();

        //添加一个新的批次  批次置为初始化
        BeanUtils.copyProperties(allocationBatchEntity, batchEntity);
        batchEntity.setStatus(AllocationBatchEnum.INIT.getStatus())
                .setBatchNo(newBatchNo)
                .setCreateDt(new Date())
                .setIsStart(0)

                .setAdminId(nextAdminId)
                .setAgentName(oneAdminByAdmin.getName())
                .setMerchantCode(allocationBatchEntity.getMerchantCode())
                .setStageCode(byAdminId.getStageCode());

        batchEntity.setGmtModified(new Date());
        batchEntity.setGmtCreate(new Date());
        allocationBatchDao.insert(batchEntity);

        //把上个批次对应的详细分单 复制到新的批次下面
        List<ClAllocationDetailEntity> listByBatchNo = allocationDetailDao.getListByBatchNo(allocationBatchEntity.getBatchNo());
        listByBatchNo.forEach(dt -> {
            if (dt.getStatus().equals(AllocationStatusEnum.INIT.getStatus()) || dt.getStatus().equals(AllocationStatusEnum.COLLECTING.getStatus())) {
                ClAllocationDetailEntity allocationDetailEntity = new ClAllocationDetailEntity();
                String allocationNo = SerialNumberUtil.getBizOrderNumber(AdminNumberRuleEnum.ALLOCATION);
                BeanUtils.copyProperties(dt, allocationDetailEntity);
                allocationDetailEntity.setBatchNo(newBatchNo);
                allocationDetailEntity.setAdminId(nextAdminId);
                allocationDetailEntity.setGmtModified(new Date());
                allocationDetailEntity.setGmtCreate(new Date());
                allocationDetailEntity.setAllocationNo(allocationNo);

                allocationDetailDao.insert(allocationDetailEntity);

                ClReceiverEntity receiverEntity = receiverDao.selectByCollectionNo(dt.getCollectionNo());
                receiverEntity.setBatchNo(newBatchNo)
                        .setCurrentAgentId(nextAdminId);
                receiverDao.updateByPrimaryKey(receiverEntity);
            }
        });

        batchEntity.setStatus(AllocationBatchEnum.SUCCESS.getStatus());
        allocationBatchDao.updateByPrimaryKey(batchEntity);
    }


    /**
     * 找到需要流转的批次，并把要流转的批次置为过期状态
     *
     * @return
     */
    private List<ClAllocationBatchEntity> getBatchNeedsTransfer() {
        List<ClAllocationBatchEntity> needTransferBatch = new ArrayList<>();
        List<ClAllocationBatchEntity> allActiveBatch = allocationBatchDao.getAllActiveBatch();
        for (ClAllocationBatchEntity batchEntity : allActiveBatch) {
            ClStageEntity stageByStageCode = stageDao.getStageByStageCode(batchEntity.getMerchantCode(), batchEntity.getStageCode());
            if (stageByStageCode == null) {
                LOGGER.error("催收步骤为空,批次需要流转,stageCode:{},batchNo:{}", batchEntity.getStageCode(), batchEntity.getBatchNo());
                needTransferBatch.add(batchEntity);
                continue;
            }

            if (stageByStageCode.getMinOverdueDays() == null) {
                LOGGER.error("催收步骤最小日期不能为空");
                continue;
            }

            if (stageByStageCode.getMaxOverdueDays() == null) {
                stageByStageCode.setMaxOverdueDays(99999999);
            }

            Date repaymentDt = batchEntity.getRepaymentDt();
            Integer overdueDays = DateUtil.diffDate(new Date(), repaymentDt);

            if (stageByStageCode.getMaxOverdueDays() != null) {
                if (!(overdueDays >= stageByStageCode.getMinOverdueDays() && overdueDays <= stageByStageCode.getMaxOverdueDays())) {
                    needTransferBatch.add(batchEntity);
                    LOGGER.info("需要更新的batch,batch:{},overdueDays:{},stageName:{}", batchEntity.getBatchNo(), overdueDays, stageByStageCode.getStageName());
                } else if (overdueDays > SystemConstants.MAX_COLLECTION_DAYS) {
                    needTransferBatch.add(batchEntity);
                    LOGGER.info("超过365天的订单需要撤回,batch:{},overdueDays:{},stageName:{}", batchEntity.getBatchNo(), overdueDays, stageByStageCode.getStageName());
                }
            }
        }
        return needTransferBatch;
    }

    /**
     * 把要流转的批次的订单都置为待分配状态
     *
     * @param batch
     */
    private void resetBatchOrdersToWaitingForAllocation(ClAllocationBatchEntity batch) {
        try {
            Integer num1 = null;
            int overdueDays = DateUtil.diffDate(new Date(), batch.getRepaymentDt());
            if (overdueDays <= 99999) {
                num1 = receiverDao.updateStatusByBatchNo(batch.getBatchNo(), ReceiverStatusEnum.INIT.getStatus());
            } else {
                num1 = receiverDao.updateStatusByBatchNo(batch.getBatchNo(), ReceiverStatusEnum.COLLECTION_END.getStatus());
            }
            batch.setStatus(AllocationBatchEnum.OVERDUE.getStatus());
            allocationBatchDao.updateByPrimaryKey(batch);
            LOGGER.info("要流转的批次的订单都置为待分配状态,成功,batch:{},num:{}", batch.getBatchNo(), num1);
        } catch (Exception e) {
            LOGGER.error("resetBatchOrdersToWaitingForAllocation异常,batch:{}", batch.getBatchNo(), e);
        }
    }

    /**
     * 用来将昨天的催收单复制到今天
     */
    private void updateBatch() {
        //把日期小于今天且分配成功的批次 状态改成待刷新
        allocationBatchDao.updateBatchSuccessToWaitingRefresh();

        //每天0点所有批次置为失效
        List<ClAllocationBatchEntity> waitingRefreshBatch = allocationBatchDao.getWaittingRefreshBatch();

        for (ClAllocationBatchEntity bt : waitingRefreshBatch) {
            LOGGER.info("处理刷新,批次号,bt:{}", JSON.toJSONString(bt));

            List<ClAllocationDetailEntity> listByBatchNo = allocationDetailDao.getListByBatchNo(bt.getBatchNo());
            LOGGER.info("处理刷新,待处理订单数,bt:{},size:{}", JSON.toJSONString(bt), listByBatchNo == null ? 0 : listByBatchNo.size());
            if (CollectionUtils.isNotEmpty(listByBatchNo)) {
                //复制出一条新的批次
                String batchNo = SerialNumberUtil.getBizOrderNumber(AdminNumberRuleEnum.BATCH);
                ClAllocationBatchEntity newBatchEntity = new ClAllocationBatchEntity();
                BeanUtils.copyProperties(bt, newBatchEntity);
                newBatchEntity.setBatchNo(batchNo)
                        .setStatus(AllocationBatchEnum.INIT.getStatus())
                        .setCreateDt(new Date())
                        .setIsStart(0);
                allocationBatchDao.insert(newBatchEntity);

                int count = 0;
                for (ClAllocationDetailEntity alDtlEntity : listByBatchNo) {
                    LOGGER.info("处理刷新的批次号,batchNo:{},collectionNo:{}", alDtlEntity.getBatchNo(), alDtlEntity.getCollectionNo());
                    if (alDtlEntity.getStatus().equals(AllocationStatusEnum.INIT.getStatus()) || alDtlEntity.getStatus().equals(AllocationStatusEnum.COLLECTING.getStatus())) {
                        ClReceiverEntity receiverEntity = receiverDao.selectByCollectionNo(alDtlEntity.getCollectionNo());
                        if (receiverEntity != null && !ReceiverStatusEnum.COLLECTION_END.getStatus().equals(receiverEntity.getStatus())) {
                            ClAllocationDetailEntity allocationDetailEntity = new ClAllocationDetailEntity();
                            String allocationNo = SerialNumberUtil.getBizOrderNumber(AdminNumberRuleEnum.ALLOCATION);
                            BeanUtils.copyProperties(alDtlEntity, allocationDetailEntity);
                            allocationDetailEntity.setBatchNo(batchNo);
                            allocationDetailEntity.setAllocationNo(allocationNo);
                            allocationDetailDao.insert(allocationDetailEntity);

                            receiverEntity.setBatchNo(batchNo);
                            receiverDao.updateByPrimaryKey(receiverEntity);
                            LOGGER.info("插入新的分单记录成功,batchNo:{},collectionNo:{},allocationNo:{}", alDtlEntity.getBatchNo(), alDtlEntity.getCollectionNo(), allocationNo);
                            count++;
                        } else {
                            LOGGER.error("处理刷新的批次号,receiver不存在记录,batchNo:{},collectionNo:{}", alDtlEntity.getBatchNo(), alDtlEntity.getCollectionNo());
                        }
                    }
                }

                if (count == 0) {
                    //兼容极端情况 如果该批次的订单都结束分单了 则把该批次置为失效
                    newBatchEntity.setStatus(AllocationBatchEnum.END.getStatus());
                } else {
                    newBatchEntity.setStatus(AllocationBatchEnum.SUCCESS.getStatus());
                }
                allocationBatchDao.updateByPrimaryKey(newBatchEntity);
            }
        }

        //将已经复制完成的订单置为失效
        waitingRefreshBatch.forEach(bt -> {
            bt.setStatus(AllocationBatchEnum.END.getStatus());
            allocationBatchDao.updateByPrimaryKey(bt);
        });
    }


}
